package controllers

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"lottery/comm"
	"lottery/models"
	"lottery/services"
	"lottery/utils"
	"lottery/web/viewmodels"
	"net/http"
	"strconv"
	"time"
)

type AdminGiftController struct {
	ServiceUser    services.UserService
	ServiceGift    services.GiftService
	ServiceCode    services.CodeService
	ServiceResult  services.ResultService
	ServiceUserday services.UserdayService
	ServiceBlackip services.BlackipService
}

// adc: AdminGiftController
// 首页
func (adc *AdminGiftController) Get(c *gin.Context) {
	// datalist 奖品列表， total 商品总数
	datalist := adc.ServiceGift.GetAll(true)
	//fmt.Println(datalist[0].PrizeData)
	//列表中的  PrizeData string 这个字段要进行一下转换才能输出给模板（时间戳转 时间）
	total := len(datalist)
	for i, gift := range datalist {
		prizeData := make([][2]int, 0)
		// 将string 类型的原数据，转换为 []byte 切片。 再进行 反序列化，存入prizeData
		err := json.Unmarshal([]byte(gift.PrizeData), &prizeData)
		if err != nil || len(prizeData) < 1 {
			// 没数据， 传递默认值进去为 "[]"
			datalist[i].PrizeData = "[]"
		} else {
			// 对 prizeData 再做一次处理, 转换
			newpd := make([]string, len(prizeData))
			for index, pd := range prizeData {
				ct := comm.FormatFromUnixTime(int64(pd[0])) // 时间
				newpd[index] = fmt.Sprintf("[%s]: %d",
					ct, pd[1]) // 转字符串处理
			}
			// 进行序列化
			str, err := json.Marshal(newpd)
			if err == nil && len(str) > 0 {
				datalist[i].PrizeData = string(str)
			} else {
				// 否则还使用默认值进去
				datalist[i].PrizeData = "[]"
			}
		}
		// （后期新增） 获取当前的奖品池数据
		// 将title 字段进行更改，显示当前商品的奖品池中的数量
		num := utils.GetGiftPoolNum(gift.Id)
		datalist[i].Title = fmt.Sprintf("【%d】%s", num, datalist[i].Title)
	}
	c.HTML(http.StatusOK, "admin/gift", gin.H{
		"Title":    "奖品",
		"Channel":  "gift",
		"Datalist": datalist,
		"Total":    total,
	})
}

// 编辑页： 查询数据
func (adc *AdminGiftController) GetEdit(c *gin.Context) {
	// 返回 giftEdit.html
	// 获取路径中的id值
	id, err := strconv.Atoi(c.DefaultQuery("id", "0"))
	if err != nil { // 设置默认值为 0
		id = 0
	}
	// 将数据转换为 ViewGift 对象，表单接受的数据
	giftInfo := viewmodels.ViewGift{}
	if id > 0 {
		// 获取数据
		data, _ := adc.ServiceGift.Get(id, true)
		// 转入 表单结构里
		giftInfo.Id = data.Id
		giftInfo.Title = data.Title
		giftInfo.PrizeNum = data.PrizeNum
		giftInfo.PrizeCode = data.PrizeCode
		giftInfo.PrizeTime = data.PrizeTime
		giftInfo.Img = data.Img
		giftInfo.Displayorder = data.Displayorder
		giftInfo.Gtype = data.Gtype
		giftInfo.Gdata = data.Gdata
		// 同样的格式转换。 发奖时间开始和结束时间 数据库中存的是 int 类型
		giftInfo.TimeBegin = comm.FormatFromUnixTime(int64(data.TimeBegin))
		giftInfo.TimeEnd = comm.FormatFromUnixTime(int64(data.TimeEnd))
	}

	c.HTML(http.StatusOK, "admin/giftEdit", gin.H{
		"Title":   "管理后台",
		"Channel": "gift",
		"info":    giftInfo,
	})
}

// 更新，新增
func (adc *AdminGiftController) PostSave(c *gin.Context) {
	// 创建数据库存储对象 及 表单对象
	giftInfo := models.LtGift{}
	data := viewmodels.ViewGift{}
	// 1. 接收数据
	err := c.ShouldBind(&data)
	if err != nil {
		// 写上日志， 数据处理错误
		fmt.Println("admin_gift.PostSave ReadForm error = ", err)
		c.JSON(http.StatusOK, gin.H{
			"Error": fmt.Sprintf("form数据转换出错： err = %s", err.Error()),
		})
	} else {
		// 数据转移进去 数据库对象
		giftInfo.Id = data.Id
		giftInfo.Title = data.Title
		giftInfo.PrizeNum = data.PrizeNum
		giftInfo.PrizeCode = data.PrizeCode
		giftInfo.PrizeTime = data.PrizeTime
		giftInfo.Img = data.Img
		giftInfo.Displayorder = data.Displayorder
		giftInfo.Gtype = data.Gtype
		giftInfo.Gdata = data.Gdata
		// 格式转换
		t1, err1 := comm.ParseTime(data.TimeBegin)
		t2, err2 := comm.ParseTime(data.TimeEnd)
		if err1 != nil || err2 != nil {
			c.JSON(http.StatusOK, gin.H{
				"Error": fmt.Sprintf("时间数据转换出错： err1 = %s , err2 = %s", err1, err2),
			})
		}
		giftInfo.TimeBegin = int(t1.Unix())
		giftInfo.TimeEnd = int(t2.Unix())
	}
	// 2. 确定数据是更新操作还是 新增操作
	if giftInfo.Id > 0 { // 更新操作
		datainfo, ok := adc.ServiceGift.Get(giftInfo.Id, true)
		if ok {
			// 更新数据： 对比修改的内容项： 如果是奖品总数发生了改变，那么整体计划就要更新
			if datainfo.PrizeNum != giftInfo.PrizeNum {
				// 奖品总数量发生了改变, 更新
				giftInfo.LeftNum = datainfo.LeftNum + (giftInfo.PrizeNum - datainfo.PrizeNum)
				if giftInfo.LeftNum < 0 || giftInfo.PrizeNum <= 0 {
					// 更新为0
					giftInfo.LeftNum = 0
				}
				// 奖品总数发生变化了， 重新计算发奖计划, 写入数据库： 发奖周期字段是单独更新的。
				// 这里主要更新了 left_num(剩余数量)， prize_data 发奖周期字段
				utils.ResetGiftPrizeData(&giftInfo, adc.ServiceGift)
			}
			if datainfo.PrizeTime != giftInfo.PrizeTime {
				// 发奖周期发生了变化， 同样需要更新发奖计划字段。
				utils.ResetGiftPrizeData(&giftInfo, adc.ServiceGift)
			}
			// 更新时间
			giftInfo.SysUpdated = int(time.Now().Unix())
			giftInfo.SysIp = comm.ClientIp(c.Request)
			// 执行更新：上面如果更新，加上这里，就进行了两次更新操作了。
			_ = adc.ServiceGift.Update(&giftInfo, []string{"title", "prize_num", "prize_code", "prize_time",
				"img", "displayorder", "gtype", "gdata", "time_begin", "time_end", "sys_updated"})
		} else {
			giftInfo.Id = 0
		}
	}
	// 创建新增
	if giftInfo.Id == 0 {
		// 其他系统字段， 需要在这里设置上
		giftInfo.LeftNum = giftInfo.PrizeNum
		giftInfo.SysIp = comm.ClientIp(c.Request)
		giftInfo.SysCreated = int(time.Now().Unix())
		// 然后创建
		adc.ServiceGift.Create(&giftInfo)
		// 然后更新发奖计划
		utils.ResetGiftPrizeData(&giftInfo, adc.ServiceGift)
	}

	// 保存成功后，进行一个跳转
	c.Redirect(http.StatusFound, "/admin/gift")
}

// 数据的删除: 状态改为 1
func (adc *AdminGiftController) GetDelete(c *gin.Context) {
	// 获取url中的id值
	id, err := strconv.Atoi(c.Query("id"))
	if err == nil { // 设置默认值为 0
		// 执行删除
		adc.ServiceGift.Delete(id)
	}
	// 恢复成功了，也跳转
	c.Redirect(http.StatusFound, "/admin/gift")
}

// 数据恢复： 状态改为 0
func (adc *AdminGiftController) GetReset(c *gin.Context) {
	// 获取路径中的id值
	id, err := strconv.Atoi(c.Query("id"))
	if err == nil { // 设置默认值为 0
		// 执行恢复
		adc.ServiceGift.Update(&models.LtGift{Id: id, SysStatus: 0}, []string{"sys_status"})
	}

	// 恢复成功了，也跳转
	c.Redirect(http.StatusFound, "/admin/gift")
}
